package controller;

import java.awt.event.*;

import javax.swing.JOptionPane;
import javax.swing.Timer;

import view.PacGameCanvas;

import model.Direction;
import model.GameEvent;
import model.GameListenerAdapter;
import model.GameModel;

import controller.GameControlCommand;

/**
 * The Control class provides control of the model.
 * 
 * @author Robert Gillespie
 * @version 0.2
 */
public class GameController extends GameListenerAdapter implements KeyListener, ActionListener{
	
	private static final String QUIT_MSG = "Are you sure you want to quit?";
	/** the following are the keys used to play the game*/
	private static final char QUIT_KEY = 'q';
	private static final char CONTINUE_KEY = ' ';
	private static final char RIGHT_KEY = 'd';
	private static final char DOWN_KEY = 's';
	private static final char LEFT_KEY = 'a';
	private static final char UP_KEY = 'w';
	private static final char WAIT_KEY = 'e';
	private static final char RESET_KEY = 'r';
	private static final int KEYPRESS_INTERVAL_MS = 200;
	
	/** The game model */
	private GameModel model;
	/** Time used for reducing the number of keyTyped events */
	private Timer wait;
	/** Execute move flag */
	private boolean useKey;
	/** reset key press flag */
	private boolean reset;
	/** level complete flag */
	private boolean levelPass;
	
	/**
	 * Creates a Console Controller for use in the tb-pacman game
	 * @param model the model for the pacman game
	 * @param view	the PacGameCanvas to listen on for key events
	 */
	public GameController(GameModel model, PacGameCanvas view){
		model.addGameListener(this);
		view.addKeyListener(this);
		this.model = model;
		wait = new Timer(KEYPRESS_INTERVAL_MS, this);
		useKey = true;
		levelPass = false;
		reset = false;
	}
	
	/**
	 * This method should handle the majority of interaction with the actual
	 * game model.
	 * @param cae	The action to perform on the game model. All possibilities
	 * 				are defined in ControlCommand enum.
	 */
	private void handleEvent(GameControlCommand cae){
		switch(cae){
			case NEW_GAME:		model.resetGame();
								levelPass = false;
								break;
			
			case RESET_LEVEL:	model.resetLevel();
								levelPass = false;
								break;
								
			case LOAD_LEVEL:	model.loadNextLevel();
								// model.resetLevel(); //Used for testing level completion
								break;
								
			case SAVE_GAME:		break;
			
			case LOAD_GAME:		break;
			
			case QUIT:			
				if (0 == JOptionPane.showConfirmDialog(null, QUIT_MSG, "Quit", JOptionPane.OK_CANCEL_OPTION)) {
					System.exit(0);
				}
			break;
								
			default:			break;
		}
	}
	
	
	/**
	 * Simple execution method that will only update the model if the useKey flag is true. 
	 * If so it will start the timer (time until next move can occur) and set the flag to
	 * false.
	 * 
	 * If w,a,s or d are pressed pacman will move in it's respective direction.
	 * If q is pressed the game will end. (Fixed)
	 */
	public void keyTyped(KeyEvent e) {
		if(useKey){
			if(reset && !model.getPlayer().isDead()) {
				model.resetLevel();
				reset = false;
				useKey = true;
				return;
			}
			
			wait.restart();
			useKey = false;
			switch(e.getKeyChar()){
				case UP_KEY: model.makeMove(Direction.NORTH); break;
				case LEFT_KEY: model.makeMove(Direction.WEST); break;
				case DOWN_KEY: model.makeMove(Direction.SOUTH); break;
				case RIGHT_KEY: model.makeMove(Direction.EAST); break;
				case WAIT_KEY: model.makeMove(null); break;
				case CONTINUE_KEY: if (levelPass) handleEvent(GameControlCommand.LOAD_LEVEL); break;
				case RESET_KEY: model.resetLevel(); model.getPlayer().resetDotsThisLife(); break;
				case QUIT_KEY: handleEvent(GameControlCommand.QUIT);
				default: break;
			}
		}
	}
	
	/**
	 * Function used to a force a new game.
	 */
	public void startNewGame() {
		handleEvent(GameControlCommand.NEW_GAME);
	}

	@Override
	public void keyPressed(KeyEvent e) {}
	@Override
	public void keyReleased(KeyEvent e) {}

	/**
	 * Resends the ActionEvent info to PerformAction()
	 */
	@Override
	public void actionPerformed(ActionEvent e) {
		
		if (e.getSource() == wait) {
			useKey = true;
			wait.restart();
		} else {
			this.handleEvent(GameControlCommand.valueOf(e.getActionCommand()));
		}
	}

	/**
	 * Should the level be completed, the control should load a new level the next
	 * time the player presses "space".
	 */
	@Override
	public void levelComplete(GameEvent event) {
		if(!model.getPlayer().isDead()) {
			levelPass = true;
		} else {
			levelPass = false;
		}
	}

	@Override
	public void playerDeath(GameEvent event) {
		reset = true;
		levelPass = false;
	}

	@Override
	public void newGame(GameEvent event) {
		levelPass = false;
	}
	@Override
	public void levelReset(GameEvent event) {
		levelPass = false;
	}
	@Override
	public void gameOver(GameEvent event) {
		levelPass = false;
	}
}
